package com.zjt.smart.manager;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Looper;
import android.text.TextUtils;

import com.zjt.smart.app.MainApplication;
import com.zjt.smart.bean.CacheBean;
import com.zjt.smart.dao.CacheBeanDao;
import com.zjt.smart.dao.DaoSession;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import okhttp3.MediaType;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import okio.Buffer;
import okio.BufferedSource;

public class CacheManager {

    private static final Charset UTF8 = Charset.forName("UTF-8");
    private static final long CACHE_DB_EXPIRE_TIME = 5*24*3600*1000;
    private DaoSession mSession;
    private SQLiteDatabase mDb;
    private CacheBeanDao mDao;

    public static CacheManager getInstance(){
        if (MainApplication.sCacheManager == null){
            MainApplication.sCacheManager = new CacheManager();
        }
        return MainApplication.sCacheManager;
    }

    private CacheManager(){
        mSession = MainApplication.getApp().getDaoSession();
        mDao = mSession.getCacheBeanDao();
        mDb = MainApplication.getApp().getDb();
    }

    public synchronized void saveCache(Request request, Response response){
        if (response == null) return;
        String responseStr = getResponseStr(response);
        if (request == null || request.url() == null || TextUtils.isEmpty(responseStr))
            return;
        long id = getCacheId(request);

        CacheBean bean = new CacheBean();
        bean.setId(id);
        bean.setUrl(request.url().toString());
        bean.setResponse(responseStr);
        bean.setTime(System.currentTimeMillis());
        mDao.insertOrReplace(bean);
    }

    public CacheBean readCache(Request request){
        long id = getCacheId(request);
        return mDao.load(id);
    }

    @SuppressWarnings("unchecked")
    public void readCacheAsync(Request request, ReadCacheCallback callback){
        new AsyncTask() {
            @Override
            protected Object doInBackground(Object[] params) {
                return readCache(request);
            }

            @Override
            protected void onPostExecute(Object o) {
                if (callback != null) {
                    if (o != null && o instanceof CacheBean) {
                        callback.onLoadCache((CacheBean) o);
                    } else {
                        callback.onLoadCache(null);
                    }
                }
            }
        }.execute();
    }

    public synchronized void removeCache(Request request){
        long id = getCacheId(request);
        mDao.deleteByKey(id);
    }

    public List<CacheBean> readAll(){
        Cursor cursor = mDb.query(mDao.getTablename(), mDao.getAllColumns(), null, null, null, null, null);
        List<CacheBean> list = new ArrayList<>();

        while (cursor.moveToNext()){
            CacheBean bean = mDao.readEntity(cursor,0);
            list.add(bean);
        }

        return list;
    }

    public void expireCache() {
        List<CacheBean> list = readAll();
        long current = System.currentTimeMillis();
        for (CacheBean bean : list) {
            if (current - bean.getTime() > CACHE_DB_EXPIRE_TIME) mDao.deleteByKey(bean.getId());
        }
    }

    public void clear(Context context){
        try {
            if (Looper.myLooper() == Looper.getMainLooper()) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        mDao.deleteAll();
                    }
                }).start();
            } else {
                mDao.deleteAll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private long getCacheId(Request request){
        String bodyStr = "";
        String urlStr = request.url() +"";
        RequestBody requestBody = request.body();
        if (requestBody != null) {
            Buffer buffer = new Buffer();
            Charset charset = UTF8;
            MediaType contentType = requestBody.contentType();
            if (contentType != null) {
                charset = contentType.charset(UTF8);
            }
            try {
                requestBody.writeTo(buffer);
                bodyStr = buffer.readString(charset);
            } catch (IOException e) {
                bodyStr = "";
            }
        }
        return  (urlStr + bodyStr).hashCode();
    }

    private String getResponseStr(Response response){
        ResponseBody responseBody = response.body();
        long contentLength = responseBody.contentLength();
        BufferedSource source = responseBody.source();
        try {
            source.request(Long.MAX_VALUE); // Buffer the entire body.
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        Buffer buffer = source.buffer();

        Charset charset = UTF8;
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(UTF8);
        }

        if (contentLength != 0) {
            return buffer.clone().readString(charset);
        }
        return null;
    }

    public interface ReadCacheCallback{
        void onLoadCache(CacheBean cache);
    }

}
